﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;

namespace Dreamz
{
    public class Program
    {
        static void Main(string[] args)
        {
            // Instantiates a GameEngine object, which takes over program control by means of its constructor
            new GameEngine();
        }
    }

    // The game engine is the root class of everything in the game, and is also what drives the game loop
    public class GameEngine
    {
        static public GameEngine S;

        // Used when saving and loading. Contains the state of all changing gameplay variables in the game.
        static public GameState GameState;
        
        public Room[,] World;
        public Player Player;
        public ConsoleScreenDrawer ScreenDrawer;

        // Initializes the game and calls the Menu() method.
        public GameEngine()
        {
            S = this;

            ScreenDrawer = new ConsoleScreenDrawer(UI.ScreenWidth, UI.ScreenHeight);
            ConsoleScreenDrawer.S = ScreenDrawer;
            ScreenDrawer.Init();

            Console.SetWindowPosition(0, 0);
            Console.CursorSize = 10;

            Menu();
        }

        // Starts the game, or loads the game.
        void StartGame(bool Continue)
        {
            UI.Console.Clear();
            if (Continue && File.Exists("savefile"))
                LoadGame();
            else
            {
                LoadWorld("rooms.txt");
                EventCode.Apply();

                Player = new Player();
                Player.X = 3;
                Player.Y = 0;
            }

            
            GameLoop();
        }

        // This method calls all the relevant methods, and provides a switch statement that accepts the input from the user.
        public void GameLoop()
        {
            bool quit = false;
            while (!quit)
            {
                ConsoleScreenDrawer.S.Clear();
                UI.Draw();

                string Command, Args;
                ParseCommandLine(Console.ReadLine(), out Command, out Args);

                switch (Command)
                {
                    case "save": SaveGame(); UI.Console.WriteLine("Game Saved"); break;

                    case "load": LoadGame(); break;

                    case "inv": Player.Look("inventory"); break;
                    case "inventory": Player.Look("inventory"); break;

                    case "tp": Player.TP(Args); break;

                    case "quit": quit = true; break;

                    case "look": Player.Look(Args); break;

                    case "go": Player.Go(Args); break;

                    case "use": Player.Use(Args); break;

                    case "pick":
                    case "take": Player.Take(Args); break;

                    case "help": Help(false); break;

                    case "n":
                    case "north": Player.Go("north"); break;

                    case "s":
                    case "south": Player.Go("south"); break;

                    case "w":
                    case "west": Player.Go("west"); break;

                    case "e":
                    case "east": Player.Go("east"); break;

                    default: UI.Console.Write("Stop this gibberish!"); break;
                }
            }
        }

        // Shows the slash screen and the main menu
        public void Menu()
        {
            // Some fancy ascii-art
            #region splash screen

            string splashString = @"    7B8ZGGG8J.  UOGG8GGOL rMMM  LBOM  ZGZGGG8k  B8ZEEEEGM:.M8OL     MG8B  YOGGGZGO, :MGGGGZGG .M8ZGGG8S:    
    :BBBBBBBBB .BBBBBBBBB,;BBB  UBBB BBBBBBBBBB BBBBBBBBBi.BBBB.   BBBBB 7BBBBBBBBB BBBBBBBBBB BBBBBBBBB7   
    ,BBBj7BBBB  BBB.'.BBB.:BBB  7BBB GBBB::BBBB BBBBBBBBBi.BBBBB  iBBBBB ;BBBY7BBBB 8BBM,,BBB8 BBBSrBBBBL   
    ,BBB ^^^^| .BBB o BBB.:BBB  iBBB NBBB  7BBB    BBB2   ,BBBBB, BBBBBB iBB''()BBB ZBB:  BBBZ BBB     .    
    ,BBB/      ,BBB. .BBB,:BBB,.ZBBB qBBB  PBBB    BBB7   :BBBBBBBBBBBBB iB|    |BB EBBv FBBBB BBB          
    ,BBB       ,BBBBBBBU  rBBBBBBBBB qBBM BBBBB    BBBj   :BBBBBBBBBBBBB iBB|  |BBB EBBBBBBB,  BBBj;7u      
    ,BBB       ,BBBBBBBi  kBBBBBBBBB qBBBBBBBB:    BBBu   :BBBBBBBBBBBBB iBBB..2BBB EBBBBBB8   BBBBBBB      
    ,BBB       ,BBBiZBBBB: . .,.NBBB qBBBBBB:      BBBu   :BBB:BBBBYUBBB iBBBBBBBBB EBBX;BBBBO BBBBBBB      
    ,BBB       .BBB  ,BBB:      :BBB qBBBB,        BBBu   :BBB  BBB LBBB iBBBBBBBBB EBBi  BBBO BBB          
    ,BBB  :uJU  BBB   BBB.rBBB  iBBB NBBB          BBBu   :BBB. MBi 0BBB iBBB  UBBB ZBBL  BBB0 BBB   77L:   
    ,BBB^^BBBB  BBB  .BBB,iBBBq :BBB BBBB          BBBP   rBBB,  B  OBBB 7BBB  ;BBB BBBJ  BBBB BBBi  BBBr   
    ,BBBJBBBBB  BBB  ,BBB.:BBBBBBBB0 0BBB          BBBL   .BBB:     BBB2 rBBB  LBBB PBBU  BBBJ BBBBB,BBB:   
    ,BBBBBBBBr   7B, iBr   .MBBBBE.   :BB         .B8.      :B7     Bq    .BB  MBi   ,BB  BP.  iBBBBBBBB:   
    ,BBBBBB7      .          ,BB.       r         .i          .     .       ;  i       ,  .      rBBBBBB:   
    ,BBBB2                                                                                         YBBBB:   
    :BBO.                                                                                            0BBi   
    YB,                                                                                               .BU   
    i                                                                                                   i   ";
            CharMap splashCharMap = new CharMap(splashString, ConsoleColor.Gray);
            

            CharMap menuCharMap = new CharMap(
                @"
  1) New Game
  2) Continue
  3) Credits
  4) Help
  5) Exit

>", ConsoleColor.White, ' ');

            for (int i = 60; i > 15; i--)
            {
                ConsoleScreenDrawer.S.Clear();
                
                ConsoleScreenDrawer.S.BufferDraw(splashCharMap, 5, i);
                ConsoleScreenDrawer.S.BufferDraw(menuCharMap, 50, 32);
                ConsoleScreenDrawer.S.Present();
                Thread.Sleep(11);
            }

            Console.SetCursorPosition(52, 39);

            #endregion

            // This is the start menu with different options.
            string option;
            option = Console.ReadLine().ToLower();
            switch (option)
            {
                case "1":
                case "new game":
                  // Starts a new game
                    StartGame(false);
                    break;
                    
                case "2":
                case "continue":
                    // Continues using sam method as start new game, but with different input parameters.
                    StartGame(true);
                    break;

                case "3":
                case "credits":
                    // Gives the user information regarding the makers of this project.
                    Console.Clear();
                    Console.WriteLine("This game is made by Pär Majholm, Jonathan Moregård, Thanh Dien Vo, Daniel Nordquist and LeTin Tram.");
                    Console.ReadKey();
                    Menu();
                    break;
                    
                case "4":
                case "help":
                    // Calls the help method, which gives a list of commands and description of what they do.
                    Help(true);
                    break;

                case "5":
                case "exit":
                    // Exits the game
                    System.Environment.Exit(1);
                    break;

            }
            Menu();
        }

        // Loads the world from a room file
        void LoadWorld(string FilePath)
        {
            World = new Room[5, 7];
            List<RoomData> roomDatas = new List<RoomData>();
            string[] roomStrings = File.ReadAllText(FilePath).Split(new string[] { "\r\n\r\n<roomspacer>\r\n\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < roomStrings.Length; i++)
                roomDatas.Add(RoomData.FromString(roomStrings[i]));
            foreach (RoomData roomData in roomDatas)
                World[roomData.X, roomData.Y] = new Room(roomData.FirstDescription, roomData.Description, roomData.North, roomData.East, roomData.South, roomData.West, roomData.Items);
        }

        // This is the help command axcessible from in-game and menu.
        public void Help(bool menu)
        {
           
            Console.Clear();
            Console.WriteLine("\tHelp Menu\n\nLook\t\tLets you inspect the room\nLook [item]\tExamines selected item\nInventory\tShows your picked items\nTake [item]\tGrabs selected item\nUse [item]\tUses selected item\n\nGo [direction]\tMoves you to chosen direction, also:\n[direction]\tChoose between north/n, west/w, south/s, east/e\n\nSave\t\tSaves the game\nHelp\t\tDisplays this information\nQuit\t\tEnds the game and returns to the main menu\n\n");
            if (!menu)
            {
                Console.WriteLine("Press any button to return to game."); 
                Console.ReadKey();
            }
            else
            {
                Console.WriteLine("Press any button to return to menu.");
                Console.ReadKey();
                Menu();
            }
        }

        // Interprets user commands.
        void ParseCommandLine(string Input, out string Command, out string Arguments)
        {
            
            char lastChar = 'a';
            for (int i = 0; i < Input.Length; i++)
            {
                if (Input[i] == ' ' && lastChar == ' ')
                {
                    Input = Input.Remove(i, 1);
                    i--;
                }
                lastChar = Input[i];
            }

            if (Input.IndexOf(' ') > -1)
            {
                Command = Input.Substring(0, Input.IndexOf(' ')).ToLower();
                Arguments = Input.Substring(Input.IndexOf(' ') + 1, Input.Length - Input.IndexOf(' ') - 1);
            }
            else
            {
                Command = Input.ToLower();
                Arguments = "";
            }
        }

        // Saves the game using Serialization
        void SaveGame()
        {
            GameState.World = World;
            GameState.Player = Player;
            GameState.Door = Door.S;
            Stream stream = File.Open("savefile", FileMode.Create);
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            bf.Serialize(stream, GameState);
            stream.Close();
        }

        // Loads the game using Serialization
        void LoadGame()
        {
            Stream stream = File.Open("savefile", FileMode.Open);
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            GameState = (GameState)bf.Deserialize(stream);
            stream.Close();
            World = GameState.World;
            Player = GameState.Player;
            Door.S = GameState.Door;
            UI.Console.Clear();
            UI.Console.Write("Game loaded");
        }

        // Easy command to write colored text
        public void WriteColored(string Text, ConsoleColor Color)
        {
            ConsoleColor normalColor = Console.ForegroundColor;
            Console.ForegroundColor = Color;
            Console.Write(Text);
            Console.ForegroundColor = normalColor;
        }

        // Easy command to write text at a certain position
        public void WriteAt(int X, int Y, string Text)
        {
            Console.SetCursorPosition(X, Y);
            Console.Write(Text);
        }
        // An overloaded function writing colored at a certain position.
        public void WriteAt(int X, int Y, string Text, ConsoleColor Color)
        {
            ConsoleColor normalColor = Console.ForegroundColor;
            Console.ForegroundColor = Color;
            Console.SetCursorPosition(X, Y);
            Console.Write(Text);
            Console.ForegroundColor = normalColor;
        }
    }

    public enum Direction { North, East, South, West }
}